# -*- coding: utf-8 -*-
"""
TMDB 工具集 - 用于处理媒体文件元数据和演员信息

功能包括：
1. 从NFO文件解析演员信息
2. 下载演员头像和元数据
3. 管理本地演员数据库

使用示例:
python tmdb_tools.py download-nfo --nfo-dir /path/to/nfo --actor-dir /path/to/actors
"""
import json
import os
import subprocess
import time
from xml.dom import minidom
from typing import Dict, List, Optional, Tuple

import requests
from requests.adapters import HTTPAdapter
from tmdbv3api import TMDb, Movie
from unipath import Path, FILES
from loguru import logger
import click

# 配置日志
logger.add("tmdb_tools.log", rotation="10 MB", level="INFO")

# TMDB API 配置
API_KEY = 'c24de12a959c4ce4b8adf7fa7f302ef9'
DOMAIN = 'http://localhost:8096'
PROXIES = {
    'http': 'socks5://127.0.0.1:7890',
    'https': 'socks5://127.0.0.1:7890'
}

# 假设的数据库模块（需要实现）
from md_help import add_item, item_exist


def get_person_info_id(person_id: int) -> Optional[Dict]:
    """
    根据演员ID获取演员详细信息

    Args:
        person_id: TMDB演员ID

    Returns:
        dict: 包含演员详细信息的字典，如果请求失败返回None

    API文档: https://developers.themoviedb.org/3/people/get-person-details
    """
    url = f'{DOMAIN}/person/{person_id}'
    headers = {'accept': 'application/json', 'Connection': 'close'}
    params = {
        'api_key': API_KEY,
        'append_to_response': 'videos,images',
        'language': 'zh'
    }

    try:
        with requests.Session() as session:
            session.mount('http://', HTTPAdapter(max_retries=3))
            session.mount('https://', HTTPAdapter(max_retries=3))
            response = session.get(url, headers=headers, params=params, proxies=PROXIES, timeout=10)
            response.raise_for_status()
            return response.json()
    except requests.RequestException as e:
        logger.error(f"获取演员ID {person_id} 信息失败: {str(e)}")
        return None


def get_person_info_name(person_name: str) -> None:
    """
    根据演员姓名搜索演员信息

    Args:
        person_name: 演员姓名

    API文档: https://developers.themoviedb.org/3/search/search-people
    """
    url = f'{DOMAIN}/search/person'
    params = {
        'api_key': API_KEY,
        'page': '1',
        'query': person_name,
        'include_adult': 'false',
        'language': 'zh'
    }

    try:
        response = requests.get(url, params=params, proxies=PROXIES, timeout=10)
        response.raise_for_status()
        logger.info(f"演员搜索结果: {response.json()}")
    except requests.RequestException as e:
        logger.error(f"搜索演员 {person_name} 失败: {str(e)}")


def download_image(image_url: str, dir_path: Path, file_name: str) -> bool:
    """
    下载图片到指定目录

    Args:
        image_url: 图片URL
        dir_path: 保存目录路径
        file_name: 保存的文件名

    Returns:
        bool: 下载是否成功
    """
    file_path = dir_path.child(file_name.replace('"', "'"))
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
        'Referer': 'https://www.themoviedb.org/'
    }

    try:
        start_time = time.time()
        with requests.Session() as session:
            response = session.get(image_url, headers=headers, stream=True, timeout=15)
            response.raise_for_status()

            with open(file_path, 'wb') as f:
                for chunk in response.iter_content(chunk_size=1024):
                    if chunk:
                        f.write(chunk)

        download_time = time.time() - start_time
        logger.success(f"图片下载成功: {file_name} [{download_time:.2f}秒]")
        return True
    except requests.RequestException as e:
        logger.error(f"图片下载失败: {file_name} - {str(e)}")
        return False


def read_nfo(nfo_file_path: Path) -> Optional[minidom.Document]:
    """
    读取并解析NFO文件

    Args:
        nfo_file_path: NFO文件路径

    Returns:
        minidom.Document: 解析后的XML文档对象，如果失败返回None
    """
    try:
        with open(nfo_file_path, 'r', encoding='utf-8') as f:
            return minidom.parse(f)
    except Exception as e:
        logger.error(f"解析NFO文件失败: {nfo_file_path} - {str(e)}")
        return None


def process_actors_in_nfo(nfo_path: Path) -> List[Dict]:
    """
    处理单个NFO文件中的演员信息

    Args:
        nfo_path: NFO文件路径

    Returns:
        list: 包含演员信息的字典列表
    """
    xml_dom = read_nfo(nfo_path)
    if not xml_dom:
        return []

    actors = []
    root = xml_dom.documentElement

    for actor_node in root.getElementsByTagName('actor'):
        actor_info = {
            'name': get_text_content(actor_node, 'name'),
            'profile': get_text_content(actor_node, 'profile'),
            'thumb': get_text_content(actor_node, 'thumb')
        }
        actors.append(actor_info)

    return actors


def get_text_content(parent_node, tag_name: str) -> str:
    """
    从XML节点中提取指定标签的文本内容

    Args:
        parent_node: 父节点
        tag_name: 目标标签名

    Returns:
        str: 标签的文本内容，如果不存在返回空字符串
    """
    nodes = parent_node.getElementsByTagName(tag_name)
    return nodes[0].childNodes[0].data if nodes and nodes[0].childNodes else ''


def download_actor_resources(actor_info: Dict,
                             save_info: bool,
                             save_image: bool,
                             info_dir: Path,
                             image_dir: Path) -> None:
    """
    下载演员资源和信息

    Args:
        actor_info: 演员信息字典
        save_info: 是否保存演员信息
        save_image: 是否保存演员图片
        info_dir: 信息保存目录
        image_dir: 图片保存目录
    """
    name = actor_info['name']
    thumb = actor_info['thumb']
    profile = actor_info['profile']

    if not name:
        logger.warning("跳过无名演员")
        return

    # 检查演员是否已存在
    if item_exist(name):
        logger.info(f"演员已存在: {name}")
        return

    # 保存演员信息
    if save_info and profile:
        try:
            person_id = int(profile.split("/")[-1])
            person_data = get_person_info_id(person_id)
            if person_data:
                info_path = info_dir.child(f"{name}.json")
                with open(info_path, 'w') as f:
                    json.dump(person_data, f, ensure_ascii=False)
                logger.info(f"演员信息保存成功: {name}")
        except (ValueError, IndexError):
            logger.error(f"无效的profile URL: {profile}")

    # 下载演员图片
    if save_image and thumb:
        try:
            file_ext = thumb.split('.')[-1].split('?')[0]
            file_name = f"{name}.{file_ext}"
            if download_image(thumb, image_dir, file_name):
                # 添加到数据库
                relative_path = str(image_dir.child(file_name)).replace("E:\\私人资料\\", "")
                add_item((thumb, name, profile, relative_path))
        except Exception as e:
            logger.error(f"图片处理失败: {name} - {str(e)}")


@click.group()
def cli():
    """TMDB 工具集命令行接口"""
    pass


@cli.command()
@click.option('--nfo-dir', required=True, type=click.Path(exists=True),
              help='包含NFO文件的根目录路径')
@click.option('--actor-dir', required=True, type=click.Path(),
              help='演员信息保存目录')
@click.option('--save-info', is_flag=True, default=False,
              help='是否保存演员详细信息')
@click.option('--save-image', is_flag=True, default=True,
              help='是否下载演员图片')
@click.option('--max-actors', default=10,
              help='每个视频文件处理的最大演员数量')
def download_nfo(nfo_dir, actor_dir, save_info, save_image, max_actors):
    """
    从NFO文件下载演员信息和图片

    遍历指定目录下的所有NFO文件，提取演员信息并下载相关资源
    """
    nfo_base = Path(nfo_dir)
    actor_base = Path(actor_dir)

    # 创建保存目录
    image_dir = actor_base.child('pic', time.strftime("%Y%m"))
    info_dir = actor_base.child('info')
    image_dir.mkdir(parents=True)
    info_dir.mkdir(parents=True)

    # 统计处理进度
    total_dirs = len(nfo_base.listdir())
    logger.info(f"开始处理 {total_dirs} 个目录")

    processed = 0
    for media_dir in nfo_base.listdir():
        processed += 1
        logger.info(f"处理进度: {processed}/{total_dirs} ({processed / total_dirs:.1%}) - {media_dir}")

        actor_count = 0
        for nfo_file in media_dir.walk(filter=FILES):
            if nfo_file.ext != '.nfo':
                continue

            try:
                actors = process_actors_in_nfo(nfo_file)
                for actor in actors:
                    if actor_count >= max_actors:
                        logger.warning(f"达到最大演员数量限制: {max_actors}")
                        break

                    download_actor_resources(actor, save_info, save_image, info_dir, image_dir)
                    actor_count += 1
                    # time.sleep(0.5)  # 避免请求过于频繁
            except Exception as e:
                logger.error(f"处理NFO文件失败: {nfo_file} - {str(e)}")

    logger.success("所有NFO文件处理完成")


@cli.command()
@click.option('--pic-dir', required=True, type=click.Path(exists=True),
              help='包含本地演员图片的目录')
def process_pic(pic_dir):
    """
    将本地图片添加到演员数据库

    遍历指定目录下的所有图片文件，将其添加到演员数据库
    """
    pic_path = Path(pic_dir)
    logger.info(f"开始处理本地图片: {pic_dir}")

    for img_file in pic_path.walk(filter=FILES):
        if img_file.ext.lower() in ('.jpg', '.jpeg', '.png'):
            try:
                actor_name = img_file.stem
                relative_path = str(img_file).replace("E:\\私人资料\\", "")
                add_item(('', actor_name, '', relative_path))
                logger.info(f"添加本地图片: {actor_name}")
            except Exception as e:
                logger.error(f"处理图片失败: {img_file} - {str(e)}")

    logger.success("本地图片处理完成")


"""
# 查看帮助
python tmdb_tools.py --help

# 处理NFO文件
python tmdb-tools-ai.py download-nfo --nfo-dir E:/emby/高清影视 --actor-dir E:/emby/video_actor_pic --max-actors 10

# 处理本地图片
python tmdb_tools.py process-pic --pic-dir /path/to/actor_images

"""
if __name__ == '__main__':
    cli()
